home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -in_the_mag- / program_perfection / gui / af_scroller.c < prev    next >
C/C++ Source or Header  |  1999-12-08  |  16KB  |  509 lines

  1. /*
  2.  * af_scroller.c
  3.  *
  4.  * Modified from ClassFree scoller.gadget
  5.  * (Needs some tidying up, yet. . .)
  6.  *
  7.  * But it now supports relativity and can be put in borders :)
  8.  *
  9.  * $Id :$
  10.  * $Log:$
  11.  *
  12.  */
  13. #include "defs.h"
  14.  
  15. #include <intuition/intuition.h>
  16. #include <intuition/classes.h>
  17. #include <intuition/icclass.h>
  18. #include <intuition/gadgetclass.h>
  19. #include <intuition/imageclass.h>
  20.  
  21. #include <proto/dos.h>
  22. #include <proto/intuition.h>
  23. #include <clib/alib_protos.h>
  24.  
  25. #include "boopsi_misc.h"
  26. #include "af_scroller.h"
  27. #include "af_button.h"
  28.  
  29.  
  30. #define     THISCLASS_ID            NULL
  31. #define     SUPERCLASS_ID           GADGETCLASS
  32. #define     SUPERCLASS_PTR          NULL
  33.  
  34.  
  35. #define     GADGET_BORDER_FLAGS     ( GACT_RIGHTBORDER | GACT_LEFTBORDER | GACT_TOPBORDER | GACT_BOTTOMBORDER )
  36.  
  37. #define     PROP_ID      0L
  38. #define     DECBTN_ID    1L
  39. #define     INCBTN_ID    2L
  40.  
  41.  
  42. /*
  43.  * Private class types
  44.  */
  45.  
  46. struct InstanceData
  47. {
  48.     Object *act;
  49.     struct Gadget *prop,*decbtn,*incbtn;
  50.     struct Image *dec_image;
  51.     struct Image *inc_image;
  52. };
  53.  
  54. /*
  55.  * Private data
  56.  */
  57.  
  58. static Class *class_base;
  59.  
  60. static ULONG SAVEDS dispatcher( REG(a0) Class *cl, REG(a2) Object *o, REG(a1) Msg msg );
  61.  
  62. static ULONG new_method( Class *cl, Object *o, struct opSet *msg );
  63. static ULONG dispose_method( Class *cl, Object *o );
  64. static ULONG set_method( Class *cl, Object *o, struct opSet *msg );
  65. static ULONG update_method( Class *cl, Object *o, Msg msg );
  66. static ULONG hittest_method( Class *cl, Object *o, Msg msg );
  67. static ULONG goactive_method( Class *cl, Object *o, Msg msg );
  68. static ULONG handleinput_method( Class *cl, Object *o, Msg msg );
  69. static ULONG goinactive_method( Class *cl, Object *o, Msg msg );
  70. static ULONG render_method( Class *cl, Object *o, Msg msg );
  71. static ULONG layout_method( Class *cl,Object *o, Msg msg );
  72.  
  73. static VOID position_gadgets( struct Gadget *scr, struct InstanceData *data, ULONG freedom );
  74. static VOID set_gadget_position( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset );
  75. static VOID set_gadget_size( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset );
  76. static BOOL hit_test_gadget( struct Gadget *gad, struct Gadget *rel_gad, struct GadgetInfo *gi,  WORD x, WORD y );
  77.  
  78. /*
  79.  * Public functions
  80.  */
  81.  
  82. Class
  83. *AFSCROLLER_GetClass(VOID)
  84. {
  85.     return class_base;
  86. }
  87.  
  88.  
  89.  
  90. VOID
  91. _INIT_7_AFSCROLLER_InitClass( VOID )
  92. {
  93.     if( class_base = MakeClass( THISCLASS_ID, SUPERCLASS_ID, SUPERCLASS_PTR, sizeof(struct InstanceData), 0L ) )
  94.     {
  95.         class_base->cl_Dispatcher.h_Entry = (ULONG (*)()) dispatcher;
  96.         return;
  97.     }
  98.     else
  99.         exit (20L);
  100. }
  101.  
  102.  
  103.  
  104. VOID
  105. _EXIT_7_AFSCROLLER_RemoveClass( VOID )
  106. {
  107.     if( class_base )
  108.         FreeClass( class_base );
  109. }
  110.  
  111.  
  112.  
  113. static ULONG SAVEDS
  114. dispatcher( REG(a0) Class *cl, REG(a2) Object *o, REG(a1) Msg msg )
  115. {
  116.     switch(msg->MethodID)
  117.     {
  118.         case OM_NEW:         return( new_method( cl, o, (struct opSet *) msg ) );
  119.         case OM_DISPOSE:     return( dispose_method( cl, o ) );
  120.         case OM_SET:         return( set_method( cl, o, (struct opSet *) msg ) );
  121.         case OM_UPDATE:      return( update_method( cl, o, msg ) );
  122.         case GM_HITTEST:     return( hittest_method( cl, o, msg ) );
  123.         case GM_GOACTIVE:
  124.         case GM_HANDLEINPUT: return( handleinput_method( cl, o, msg ) );
  125.         case GM_GOINACTIVE:  return( goinactive_method( cl, o, msg ) );
  126.         case GM_RENDER:      return( render_method( cl, o, msg ) );
  127.         case GM_LAYOUT:      return( layout_method( cl, o, msg ) );
  128.  
  129.         default:             return( DoSuperMethodA(cl,o,msg) );
  130.     }
  131. }
  132.  
  133.  
  134. static ULONG
  135. new_method( Class *cl, Object *o, struct opSet *msg )
  136. {
  137.     struct TagItem  *attrs = msg->ops_AttrList;
  138.     struct Gadget   *scr;
  139.     struct DrawInfo *dri;
  140.     WORD   oldfill;
  141.  
  142.  
  143.     if( scr = (struct Gadget *) DoSuperMethodA( cl, o, (Msg) msg ) )
  144.     {
  145.         if( !( dri = (struct DrawInfo *) GetTagData( GA_DrawInfo,NULL, attrs ) ) )
  146.         {
  147.             DoSuperMethod( (Class *)o, (Object *) scr, OM_DISPOSE );
  148.         }
  149.         else
  150.         {
  151.             ULONG size    = GetTagData( SYSIA_Size, SYSISIZE_MEDRES, attrs );
  152.             ULONG fdm     = GetTagData( PGA_Freedom, FREEVERT, attrs );
  153.             ULONG total   = GetTagData( PGA_Total, 1, attrs );
  154.             ULONG visible = GetTagData( PGA_Visible, 1, attrs );
  155.             ULONG top     = GetTagData( PGA_Top, 0, attrs );
  156.  
  157.             struct InstanceData *data = INST_DATA( cl ,scr );
  158.  
  159.             /* Change fill color */
  160.             if( !( scr->Activation & GADGET_BORDER_FLAGS ) )
  161.             {
  162.                 oldfill = dri->dri_Pens[ FILLPEN ];
  163.                 dri->dri_Pens[ FILLPEN ] = 0;
  164.             }
  165.  
  166.             data->dec_image = (struct Image *) NewObject( NULL, SYSICLASS,
  167.                                                     SYSIA_Which,    (fdm == FREEVERT) ? UPIMAGE : LEFTIMAGE,
  168.                                                     SYSIA_DrawInfo, dri,
  169.                                                     SYSIA_Size,     size,
  170.                                                 TAG_DONE );
  171.  
  172.             data->inc_image = (struct Image *) NewObject( NULL, SYSICLASS,
  173.                                                     SYSIA_Which,    (fdm == FREEVERT) ? DOWNIMAGE : RIGHTIMAGE,
  174.                                                     SYSIA_DrawInfo, dri,
  175.                                                     SYSIA_Size,     size,
  176.                                                 TAG_DONE );
  177.  
  178.             if( !( scr->Activation & GADGET_BORDER_FLAGS ) )
  179.                 dri->dri_Pens[FILLPEN] = oldfill;
  180.  
  181.             if( data->dec_image && data->inc_image )
  182.             {
  183.                 data->prop = NewObject( NULL,PROPGCLASS,
  184.                                                    PGA_Freedom,    fdm,
  185.                                                    PGA_NewLook,    TRUE,
  186.                                                    PGA_Borderless, TRUE,
  187.                                                    PGA_Total,      total,
  188.                                                    PGA_Visible,    visible,
  189.                                                    PGA_Top,        top,
  190.                                                    ICA_TARGET,     scr,
  191.                                                    GA_ID,          PROP_ID,
  192.                                                TAG_DONE );
  193.  
  194.                 data->decbtn = NewObject( AFBUTTON_GetClass(), NULL,
  195.                                                    GA_Image,   data->dec_image,
  196.                                                    GA_ID,      DECBTN_ID,
  197.                                                    ICA_TARGET, scr,
  198.                                                TAG_DONE );
  199.  
  200.                 data->incbtn = NewObject( AFBUTTON_GetClass(), NULL,
  201.                                                    GA_Image,   data->inc_image,
  202.                                                    GA_ID,      INCBTN_ID,
  203.                                                    ICA_TARGET, scr,
  204.                                                TAG_DONE );
  205.  
  206.  
  207.                 if( data->prop && data->decbtn && data->incbtn )
  208.                 {
  209.  
  210.                     position_gadgets( scr, data, fdm );
  211.  
  212.                     return (ULONG)scr;
  213.                 }
  214.             }
  215.             DoMethod( (Object *) scr, OM_DISPOSE );
  216.         }
  217.     }
  218.     return 0L;
  219. }
  220.  
  221.  
  222. static ULONG
  223. dispose_method( Class *cl, Object *o )
  224. {
  225.     struct InstanceData *data = INST_DATA( cl, o );
  226.  
  227.     if( data->prop )      { DisposeObject( (Object *) data->prop   );    data->prop   =    NULL; }
  228.     if( data->incbtn )    { DisposeObject( (Object *) data->incbtn );    data->incbtn =    NULL; }
  229.     if( data->decbtn )    { DisposeObject( (Object *) data->decbtn );    data->decbtn =    NULL; }
  230.     if( data->inc_image ) { DisposeObject( (Object *) data->inc_image ); data->inc_image = NULL; }
  231.     if( data->dec_image ) { DisposeObject( (Object *) data->dec_image ); data->dec_image = NULL; }
  232.  
  233.     DoSuperMethod( cl, o, OM_DISPOSE );
  234.  
  235.     return 0L;
  236. }
  237.  
  238. static ULONG
  239. set_method( Class *cl, Object *o, struct opSet *msg )
  240. {
  241.   struct Gadget       *scr   = (struct Gadget *) o;
  242.   struct InstanceData *data  = (struct InstanceData *)INST_DATA(cl,o);
  243.   struct TagItem      *attrs = msg->ops_AttrList;
  244.   Tag filter[] = { PGA_Top, PGA_Visible, PGA_Total, TAG_DONE };
  245.   ULONG freedom;
  246.  
  247.   DoSuperMethodA( cl, o, (Msg) msg );
  248.  
  249.   FilterTagItems( attrs, filter, TAGFILTER_AND );
  250.   DoMethodA( (Object *) data->prop, (Msg) msg );
  251.  
  252.   freedom = (data->decbtn->LeftEdge == data->incbtn->LeftEdge) ? FREEVERT : FREEHORIZ;
  253.  
  254.   position_gadgets( scr, data, freedom );
  255.  
  256.   return 0L;
  257. }
  258.  
  259.  
  260. static ULONG
  261. update_method( Class *cl, Object *o, Msg msg )
  262. {
  263.   struct opUpdate *updin = (struct opUpdate *)msg;
  264.   struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
  265.   struct Gadget *scr = (struct Gadget *)o;
  266.   struct opUpdate upd;
  267.   struct TagItem tag[5];
  268.   ULONG id,top,newtop;
  269.  
  270.     id = GetTagData(GA_ID,0,updin->opu_AttrList);
  271.  
  272.     top = QuickGetAttr( data->prop, PGA_Top );
  273. /*  DoMethod((Object *)data->prop,OM_GET,PGA_Top,&top); */
  274.   /* An update message is used for both OM_SET and OM_NOTIFY
  275.      since the messages are so much alike. */
  276.   upd.MethodID = OM_SET;
  277.   upd.opu_AttrList = tag;
  278.   upd.opu_GInfo = updin->opu_GInfo;
  279.   upd.opu_Flags = updin->opu_Flags;
  280.   /*
  281.    Only enter this if its a button update and an interrim message
  282.    Problem: First update message must emulate the gadgetdown message
  283.    */
  284.   if(id>0&&updin->opu_Flags&OPUF_INTERIM)
  285.   {
  286.       if( id==DECBTN_ID ) newtop = top-1;
  287.       if( id==INCBTN_ID ) newtop = top+1;
  288.       tag[0].ti_Tag = PGA_Top; tag[0].ti_Data = newtop;
  289.       tag[1].ti_Tag = TAG_DONE;
  290.       /* Prevent backwards overrun, forwards overrun is prevented
  291.         by propgadget */
  292.       if(newtop!=-1)  DoMethodA((Object *)data->prop,(Msg)&upd);
  293.  
  294.       /* Initial check to prevent notification messages in case of overrun */
  295.       top = QuickGetAttr( data->prop, PGA_Top );
  296. /*      DoMethod((Object *)data->prop,OM_GET,PGA_Top,&top); */
  297.   }
  298.   /* Only enter if interim message or message from propg */
  299.   if( updin->opu_Flags&OPUF_INTERIM || id == PROP_ID )
  300.   {
  301.     /* Prevent notification in case of overrun */
  302.     if( id != PROP_ID && top != newtop) return(0);
  303.     /* Notify */
  304. /*    upd.MethodID = OM_NOTIFY;
  305.     tag[0].ti_Tag = PGA_Top; tag[0].ti_Data = top;
  306.     tag[1].ti_Tag = GA_ID; tag[1].ti_Data = scr->GadgetID;
  307.     tag[2].ti_Tag = TAG_DONE;
  308.     DoMethodA(o,(Msg)&upd); */
  309.     NotifyAttrChanges( o, updin->opu_GInfo, updin->opu_Flags, PGA_Top, top, GA_ID, scr->GadgetID, TAG_DONE );
  310.   }
  311.   return 0L;
  312. }
  313.  
  314.  
  315. static ULONG
  316. hittest_method( Class *cl, Object *o, Msg msg )
  317. {
  318.     struct gpHitTest    *test = (struct gpHitTest *)msg;
  319.     struct Gadget       *scr  = (struct Gadget *)o;
  320.     struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
  321.     WORD x = test->gpht_Mouse.X ,y = test->gpht_Mouse.Y;
  322.  
  323.  
  324.     if( hit_test_gadget( data->prop, scr, test->gpht_GInfo, x, y ) )
  325.     {
  326.         data->act = (Object *)data->prop;
  327.         return GMR_GADGETHIT;
  328.     }
  329.  
  330.     if( hit_test_gadget( data->decbtn, scr, test->gpht_GInfo, x, y ) )
  331.     {
  332.         data->act = (Object *)data->decbtn;
  333.         return GMR_GADGETHIT;
  334.     }
  335.  
  336.     if( hit_test_gadget( data->incbtn, scr, test->gpht_GInfo, x, y ) )
  337.     {
  338.         data->act = (Object *)data->incbtn;
  339.         return GMR_GADGETHIT;
  340.     }
  341.  
  342.     return 0L;
  343. }
  344.  
  345. static ULONG
  346. goactive_method( Class *cl, Object *o, Msg msg )
  347. {
  348.   struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
  349.   struct gpInput *in = (struct gpInput *)msg;
  350.   struct Gadget *act = (struct Gadget *)data->act, *scr = (struct Gadget *)o;
  351.   ULONG result;
  352.  
  353.   in->gpi_Mouse.X -= act->LeftEdge-scr->LeftEdge;
  354.   in->gpi_Mouse.Y -= act->TopEdge-scr->TopEdge;
  355.   result = DoMethodA(data->act,msg);
  356.  
  357.   return result;
  358. }
  359.  
  360. static ULONG
  361. handleinput_method( Class *cl, Object *o, Msg msg )
  362. {
  363.   struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
  364.   struct gpInput *in = (struct gpInput *)msg;
  365.   struct Gadget *act = (struct Gadget *)data->act, *scr = (struct Gadget *)o;
  366.   ULONG result;
  367.  
  368.   in->gpi_Mouse.X -= act->LeftEdge-scr->LeftEdge;
  369.   in->gpi_Mouse.Y -= act->TopEdge-scr->TopEdge;
  370.   result = DoMethodA(data->act,msg);
  371.   if(result)
  372.   {
  373.     if(scr->Activation&GACT_RELVERIFY)
  374.     {
  375.       result |= GMR_VERIFY;
  376.       *(in->gpi_Termination) = QuickGetAttr( data->prop, PGA_Top );
  377.     }
  378.     else
  379.     {
  380.       result &= ~GMR_VERIFY;
  381.     }
  382.   }
  383.  
  384.   return result;
  385. }
  386.  
  387.  
  388. static ULONG
  389. goinactive_method( Class *cl, Object *o, Msg msg )
  390. {
  391.   struct InstanceData *data = (struct InstanceData *) INST_DATA( cl, o );
  392.   ULONG result;
  393.  
  394.   result = DoMethodA(data->act,msg);
  395.   data->act = NULL;
  396.  
  397.   return result;
  398. }
  399.  
  400.  
  401. static ULONG
  402. render_method( Class *cl, Object *o, Msg msg )
  403. {
  404.   struct gpRender *rend = (struct gpRender *)msg;
  405.   struct InstanceData *data = INST_DATA( cl, o );
  406.  
  407.   DoMethodA( (Object *) data->prop,msg);
  408.   DoMethodA( (Object *) data->decbtn,msg);
  409.   DoMethodA( (Object *) data->incbtn,msg);
  410.  
  411.   return 1L;
  412. }
  413.  
  414.  
  415. static ULONG
  416. layout_method( Class *cl,Object *o, Msg msg )
  417. {
  418.     struct gpLayout     *lay  = (struct gpLayout *)msg;
  419.     struct GadgetInfo   *gi   = lay->gpl_GInfo;
  420.     struct Gadget       *scr  = (struct Gadget *)o;
  421.     struct InstanceData *data = (struct InstanceData *)INST_DATA(cl,o);
  422.  
  423.     if( scr->Flags & GFLG_RELWIDTH )
  424.     {
  425.         data->incbtn->LeftEdge = scr->LeftEdge + gi->gi_Domain.Width + scr->Width - data->incbtn->Width;
  426.         data->decbtn->LeftEdge = data->incbtn->LeftEdge - data->decbtn->Width;
  427.     }
  428.  
  429.     if( scr->Flags & GFLG_RELHEIGHT )
  430.     {
  431.         data->incbtn->TopEdge = scr->TopEdge + gi->gi_Domain.Height + scr->Height - data->incbtn->Height;
  432.         data->decbtn->TopEdge = data->incbtn->TopEdge - data->decbtn->Height;
  433.     }
  434.  
  435.     return 1L;
  436. }
  437.  
  438.  
  439.  
  440. static VOID
  441. position_gadgets( struct Gadget *scr, struct InstanceData *data, ULONG freedom )
  442. {
  443.     UWORD x, y;
  444.  
  445.     if( freedom == FREEVERT)
  446.     {
  447.         scr->Width = data->incbtn->Width;
  448.         x = 0;
  449.         y = data->decbtn->Height*2;
  450.     }
  451.     else
  452.     {
  453.         x = data->decbtn->Width*2;
  454.         scr->Height = data->decbtn->Height;
  455.         y = 0;
  456.     }
  457.  
  458.     set_gadget_position( scr, data->prop, 4, 2 );
  459.     set_gadget_size( scr, data->prop, x+8, y+4  );
  460.  
  461.     if(freedom == FREEVERT)
  462.         y = scr->Height - data->incbtn->Height;
  463.     else
  464.         x = scr->Width  - data->incbtn->Width;
  465.  
  466.     set_gadget_position( scr, data->incbtn, x, y );
  467.  
  468.     if(freedom == FREEVERT)
  469.         y -= data->decbtn->Height;
  470.     else
  471.         x -= data->decbtn->Width;
  472.  
  473.     set_gadget_position( scr, data->decbtn, x, y );
  474.  
  475.     return;
  476. }
  477.  
  478. static VOID
  479. set_gadget_position( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset )
  480. {
  481.     dest->LeftEdge    = source->LeftEdge + x_offset;
  482.     dest->TopEdge     = source->TopEdge  + y_offset;
  483.     dest->Flags      |= source->Flags & ( GFLG_RELRIGHT | GFLG_RELBOTTOM );
  484.     dest->Activation |= source->Activation & GADGET_BORDER_FLAGS;
  485.  
  486.     return;
  487. }
  488.  
  489. static VOID
  490. set_gadget_size( struct Gadget *source, struct Gadget *dest, UWORD x_offset, UWORD y_offset )
  491. {
  492.     dest->Width  =  source->Width  - x_offset;
  493.     dest->Height =  source->Height - y_offset;
  494.     dest->Flags |= ( source->Flags & ( GFLG_RELWIDTH | GFLG_RELHEIGHT ));
  495.  
  496.     return;
  497. }
  498.  
  499. static BOOL
  500. hit_test_gadget( struct Gadget *gad, struct Gadget *rel_gad, struct GadgetInfo *gi,  WORD x, WORD y )
  501. {
  502.     UWORD gx = gad->LeftEdge - rel_gad->LeftEdge;
  503.     UWORD gy = gad->TopEdge  - rel_gad->TopEdge;
  504.     UWORD gw = (gad->Flags & GFLG_RELWIDTH)  ? gx + gi->gi_Domain.Width  + gad->Width  : gx + gad->Width;
  505.     UWORD gh = (gad->Flags & GFLG_RELHEIGHT) ? gy + gi->gi_Domain.Height + gad->Height : gy + gad->Height;
  506.  
  507.     return ( x >= gx && x <= gw && y >= gy && y <= gh );
  508. }
  509.